home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / ISSUE02 / TPACK / TPACK.ZIP / BITBOX.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-06-01  |  15.1 KB  |  539 lines

  1. {------------------------------------------------------------------------------}
  2. {UNREGISTERED VERSION (6/1/95) PLEASE REDISTRIBUTE IN tPACK.ZIP!
  3.  This revision does not contain everything, nor are the exciting
  4.  DataSetReporter and ExtendedMenu[Item] components included.
  5.  Use SWREG#5906 to receive these, icons and a help file for $130.
  6.  You must register when using this code in a business application!
  7.  You'll receive a license to use this code in up to 50 copies of
  8.  any app you write. In turn you will get responsive e-mail
  9.  tech support and enhancements till I run out of registrations
  10.  or suggestions. Meanwhile.. enjoy the code. Bye! I'll make more.
  11.  {(C)'1995 Michael/Ax-Systems, 71560,1754@Compuserve.com}
  12. {------------------------------------------------------------------------------}
  13.  
  14. unit Bitbox;
  15.  
  16. {The SECOND implementation
  17. does multiple columns and rows smartly.
  18. understands text better.
  19. resizes imperfectly still}
  20.  
  21. {BitBox like Toolbars anyone? just kidding}
  22.  
  23. {THE POINT:  To create checkbox group components that will take a byte or word
  24. and provide dynamically sized boxes containing selected items from a universe
  25. of 8 or 16 choices. Allowing the user to check/set bits via a form.}
  26.  
  27. {this unit takes advantage of delphi's small set implementation, which works
  28. in bytes and words for sets with less than 9/17 members respectively.}
  29.  
  30. interface
  31.  
  32. uses
  33.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  34.   Forms, Dialogs, DB, DBTables, StdCtrls;
  35.  
  36. type
  37.   {define the word compatible set}
  38.   T16Bits = (Bit0,Bit1,Bit2,Bit3,Bit4,Bit5,Bit6,Bit7
  39.             ,Bit8,Bit9,BitA,BitB,BitC,BitD,BitE,BitF);
  40.   TWordSet = Set of T16Bits;
  41.   TWord = Record
  42.     x:Word;
  43.     end;
  44.  
  45.   TBoxOrientation = (boxVertical,boxHorizontal);
  46.  
  47.   {define a common groupbox for byte and word use}
  48.   TBitBox = class(TGroupBox)
  49.   private
  50.     fMembers: TWordSet;
  51.     fMask: TWordSet;
  52.     fCaptions: TStringList;
  53.     fHints: TStringList;
  54.     fOnChange: TNotifyEvent;
  55.     fReadOnly: Boolean;
  56.  
  57.     fBoxOrientation: TBoxOrientation;
  58.     fFromLeft: Byte;
  59.     fFromRight: Byte;
  60.     fColumns: Byte;
  61.     fMinTextWidth:Byte;
  62.     fMaxTextWidth:Integer;
  63.     fFromTop:Byte;
  64.     fRowHeight:Byte;
  65.     fColumnSpacing:Byte;
  66.  
  67.     procedure ChangeSelected(Sender:TObject); virtual;
  68.   protected
  69.     function GetMember:Word;
  70.     procedure SetMember(Value:Word);
  71.     procedure SetMembers(Value:TWordSet);
  72.     procedure SetMask(Value:TWordSet);
  73.     procedure SetCaptions(Value:TStringList);
  74.     procedure SetHints(Value:TStringList);
  75.     function GetMaxTextWidth:Integer;
  76.     procedure SetColumns(Value:Byte);
  77.     procedure SetFromTop(Value:Byte);
  78.     procedure SetRowHeight(Value:Byte);
  79.     procedure SetMinTextWidth(Value:Byte);
  80.     procedure SetMaxTextWidth(Value:Integer);
  81.     procedure SetColumnSpacing(Value:Byte);
  82.     procedure SetBoxOrientation(Value:TBoxOrientation);
  83.     procedure InitBox;
  84.   public
  85.     constructor Create(aOwner:TComponent); Override;
  86.     destructor Destroy; Override;
  87.     procedure Loaded; Override;
  88.     procedure Init; {[re]creates checkboxes from fUniverse/fMembers}
  89.     procedure UpdateAll;
  90.     procedure Update(Bit:T16Bits;aChecked:Boolean;aCaption:String); {updates chekbox}
  91.   published
  92.     property Numeric:  Word read GetMember write SetMember;
  93.     property Possible: TWordSet read fMask write SetMask;
  94.     property Selected: TWordSet read fMembers write SetMembers;
  95.     property ReadOnly: Boolean read fReadOnly write fReadOnly default False;
  96.     property Captions: TStringList read fCaptions write SetCaptions;
  97.     property Hints:    TStringList read fHints write SetHints;
  98.     property OnChange: TNotifyEvent read fOnChange write fOnChange;
  99.  
  100.     property BoxOrientation: TBoxOrientation read fBoxOrientation write SetBoxOrientation
  101.     {$IFDEF START_HORIZONTALLY}
  102.       default boxHorizontal;
  103.     {$ELSE}
  104.       default boxVertical;
  105.     {$ENDIF}
  106.     property Columns: Byte read fColumns write SetColumns
  107.     {$IFDEF START_HORIZONTALLY}
  108.       default 0;
  109.     {$ELSE}
  110.       default 2;
  111.     {$ENDIF}
  112.     property FromTop: Byte read fFromTop write fFromTop default 20;
  113.     property FromLeft: Byte read fFromLeft write fFromLeft default 10;
  114.     property FromRight: Byte read fFromRight write fFromRight default 5;
  115.     property RowHeight: Byte read fRowHeight write SetRowHeight default 20;
  116.     property ColumnSpacing:Byte read fColumnSpacing write SetColumnSpacing default 10;
  117.     property MinTextWidth:Byte read fMinTextWidth write SetMinTextWidth default 16;
  118.     property MaxTextWidth:Integer read GetMaxTextWidth write SetMaxTextWidth;
  119.     end;
  120.  
  121.   TdbBitBox = class(TBitBox)
  122.   private
  123.     FDataLink: TFieldDataLink;
  124.     procedure DataChange(Sender: TObject);
  125.     function GetDataField: string;
  126.     function GetDataSource: TDataSource;
  127.     function GetField: TField;
  128.     procedure SetDataField(const Value: string);
  129.     procedure SetDataSource(Value: TDataSource);
  130.     procedure ChangeSelected(Sender:TObject); override;
  131.     procedure UpdateData(Sender: TObject);
  132.     procedure EditingChange(Sender: TObject);
  133.   protected
  134.     function GetReadOnly: Boolean;
  135.     procedure SetReadOnly(Value: Boolean);
  136.     procedure Notification(AComponent: TComponent;
  137.       Operation: TOperation); override;
  138.   public
  139.     constructor Create(aOwner:TComponent); Override;
  140.     destructor Destroy; Override;
  141.     property Field: TField read GetField;
  142.   published
  143.     property DataField: string read GetDataField write SetDataField;
  144.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  145.     end;
  146.  
  147.  
  148. implementation
  149.  
  150. {------------------------------------------------------------------------------}
  151. { CREATE, PREPARE AND DISPOSE OF THE COMPONENT                                 }
  152. {------------------------------------------------------------------------------}
  153.  
  154. constructor TBitBox.Create(aOwner:TComponent);
  155. var
  156.   Bit: T16Bits;
  157. begin
  158.   inherited Create(aOwner);
  159.   fColumnSpacing:=10;
  160.   fFromTop:=20;
  161.   fFromLeft:=10;
  162.   fFromRight:=5;
  163.   fRowHeight:=20;
  164.   fMinTextWidth:=13;
  165.   {$IFDEF START_HORIZONTALLY}
  166.     fBoxOrientation:=boxHorizontal;
  167.     fColumns:=0;
  168.   {$ELSE}
  169.     fBoxOrientation:=boxVertical;
  170.     fMaxTextWidth:=100;
  171.     fColumns:=2;
  172.   {$ENDIF}
  173.   fCaptions:=TStringList.Create;
  174.   fHints:=TStringList.Create;
  175.   for Bit:= Bit0 to BitF do begin
  176.     Include(fMask,Bit);
  177.     fCaptions.Add('(Bit'+inttoStr(ord(bit))+')');
  178.     fHints.Add('(Bit'+inttoStr(ord(bit))+')');
  179.     end;
  180. end;
  181.  
  182. procedure TBitBox.Loaded;
  183. begin
  184.   inherited Loaded;
  185.   InitBox;
  186. end;
  187.  
  188. destructor TBitBox.Destroy;
  189. begin
  190.   fCaptions.Free;
  191.   fCaptions:=nil;
  192.   fHints.Free;
  193.   fHints:=nil;
  194.   inherited Destroy;
  195. end;
  196.  
  197. {------------------------------------------------------------------------------}
  198. { GET AND SET THE COMPONENT SPECIFIC PROPERTIES                                }
  199. {------------------------------------------------------------------------------}
  200.  
  201. function TBitBox.GetMember:Word;
  202. var
  203.   s:TWordSet;
  204. begin
  205.   s:=fMembers;
  206.   result:=tWord(s).x;
  207. end;
  208.  
  209. procedure TBitBox.SetMember(Value:Word);
  210. var
  211.   s:TWordSet;
  212. begin
  213.   s:=TWordSet(Value);
  214.   SetMembers(s);
  215. end;
  216.  
  217. procedure TBitBox.SetMembers(Value:TWordSet);
  218. begin
  219.   if fMembers<>Value then begin
  220.     fMembers:=Value;
  221.     UpdateAll;
  222.     end;
  223. end;
  224.  
  225. procedure TBitBox.SetMask(Value:TWordSet);
  226. begin
  227.   if fMask<>Value then begin
  228.     fMask:=Value;
  229.     init;
  230.     end;
  231. end;
  232.  
  233. procedure TBitBox.SetCaptions(Value:TStringList);
  234. begin
  235.   if fCaptions<>Value then begin {wow}
  236.     fCaptions.Assign(Value);
  237.     UpdateAll;
  238.     end;
  239. end;
  240.  
  241. procedure TBitBox.SetHints(Value:TStringList);
  242. begin
  243.   if fHints<>Value then begin
  244.     fHints.Assign(Value);
  245.     UpdateAll;
  246.     end;
  247. end;
  248.  
  249. procedure TBitBox.SetColumns(Value:Byte);
  250. begin
  251.   if fColumns<>Value then begin
  252.     fColumns:=Value;
  253.     Init;
  254.     end;
  255. end;
  256.  
  257. procedure TBitBox.SetRowHeight(Value:Byte);
  258. begin
  259.   if fRowHeight<>Value then begin
  260.     fRowHeight:=Value;
  261.     Init;
  262.     end;
  263. end;
  264.  
  265. procedure TBitBox.SetBoxOrientation(Value:TBoxOrientation);
  266. begin
  267.   if fBoxOrientation<>Value then begin
  268.     fBoxOrientation:=Value;
  269.     Init;
  270.     end;
  271. end;
  272.  
  273. procedure TBitBox.SetMinTextWidth(Value:Byte);
  274. begin
  275.   if fMinTextWidth<>Value then begin
  276.     fMinTextWidth:=Value;
  277.     Init;
  278.     end;
  279. end;
  280.  
  281. function TBitBox.GetMaxTextWidth:Integer;
  282. begin
  283.   if fMaxTextWidth<fMinTextWidth then
  284.     fMaxTextWidth:=fMinTextWidth;
  285.   Result:= fMaxTextWidth;
  286. end;
  287.  
  288. procedure TBitBox.SetMaxTextWidth(Value:Integer);
  289. begin
  290.   if fMaxTextWidth<>Value then begin
  291.     fMaxTextWidth:=Value;
  292.     Init;
  293.     end;
  294. end;
  295.  
  296. procedure TBitBox.SetColumnSpacing(Value:Byte);
  297. begin
  298.   if fColumnSpacing<>Value then begin
  299.     fColumnSpacing:=Value;
  300.     Init;
  301.     end;
  302. end;
  303.  
  304. procedure TBitBox.SetFromTop(Value:Byte);
  305. begin
  306.   if fFromTop<>Value then begin
  307.     fFromTop:=Value;
  308.     Init;
  309.     end;
  310. end;
  311.  
  312. {------------------------------------------------------------------------------}
  313. { INITIALIZE AND UPDATE ALL OR ONE CHECKBOX IN THE GROUP                       }
  314. {------------------------------------------------------------------------------}
  315.  
  316. procedure TBitBox.Init;
  317. begin
  318.   if not (csLoading in ComponentState) then
  319.     InitBox;
  320. end;
  321.  
  322. procedure TBitBox.InitBox;
  323. var
  324.   Cols,i,n:integer;
  325.   Bit:T16Bits;
  326.   c:TCheckBox;
  327.   col,row,percol:byte;
  328. begin
  329.   n:=ControlCount-1;
  330.   if n>-1 then
  331.     for i:=0 to n do
  332.       Controls[0].Free;     {free all owned controls. really.}
  333.   n:=0;
  334.   for bit:= Bit0 to BitF do {step and count how many we'll be making}
  335.     if bit in fMask then
  336.       n:=n+1;
  337.   if n=0 then {nothing to do} {shrink?}
  338.     exit;
  339.   Cols:=fColumns;
  340.   if Cols<=0 then
  341.     Cols:=1;
  342.   if (fBoxOrientation=boxHorizontal) and (fColumns<2) then
  343.     Cols:=n;  {adjust to all accross.}
  344.   percol:=n div Cols;          {figure out how many rows that'll be}
  345.   if (n mod Cols) >0 then  {adjust to get 2 rows for 3 items in 2 columns}
  346.     percol:=percol+1;
  347.   i:=FromLeft+FromRight+Cols*(fColumnSpacing+MaxTextWidth);
  348.   if Width<i then
  349.     Width:=i;
  350.   row:=0;
  351.   col:=0;
  352.   for bit:= Bit0 to BitF do
  353.     if bit in fMask then begin  {make new child controls}
  354.       c:=TCheckBox.Create(self);
  355.       with c do begin
  356.         Checked:= bit in fMembers;
  357.         end;
  358.       with c do begin
  359.         Tag:=ord(bit);
  360.         Caption:= fCaptions.Strings[Tag];
  361.         Hint:= fHints.Strings[Tag];
  362.         Parent:=Self;
  363.         OnClick:=ChangeSelected;
  364.         Left:=FromLeft+Col*(fColumnSpacing+fMaxTextWidth);
  365.         Width:=MaxTextWidth;
  366.         Top:=fFromTop+(Row*fRowHeight);
  367.         if fBoxOrientation=boxVertical then begin
  368.           Row:=row+1;
  369.           if Row=PerCol then begin
  370.             Row:=0;
  371.             Col:=Col+1;
  372.             end;
  373.           end
  374.         else begin
  375.           Col:=Col+1;
  376.           if Cols=Cols then begin
  377.             Col:=0;
  378.             Row:=Row+1;
  379.             end;
  380.           end;
  381.         end;
  382.       end;
  383.   if Height<(fRowHeight*(PerCol+1)) then;
  384.     Height:=(fRowHeight*(PerCol+1));
  385. end;
  386.  
  387. procedure TBitBox.UpdateAll;
  388. var
  389.   Bit:T16Bits;
  390. begin
  391.   for Bit:= Bit0 to BitF do
  392.     if Bit in fMask then
  393.       Update(Bit,Bit in fMembers,fCaptions.Strings[ord(Bit)])
  394. end;
  395.  
  396. procedure TBitBox.Update(Bit:T16Bits;aChecked:Boolean;aCaption:String);
  397. var
  398.   i,n:integer;
  399. begin
  400.   n:=ControlCount-1;
  401.   if n>-1 then
  402.     for i:=0 to n do
  403.       if Controls[i].Tag=ord(Bit) then
  404.         with TCheckBox(Controls[i]) do begin
  405.           Caption:=aCaption;
  406.           Checked:=aChecked;
  407.           break;
  408.           end;
  409. end;
  410.  
  411. {------------------------------------------------------------------------------}
  412. { PROCS FOR CUSTOM EVENTS                                                      }
  413. {------------------------------------------------------------------------------}
  414.  
  415. procedure TBitBox.ChangeSelected(Sender:TObject);
  416. var
  417.   c:TCheckBox;
  418.   b:T16Bits;
  419. begin
  420.   c:=TCheckBox(Sender);
  421.   b:=T16Bits(c.Tag); {remember, we're using the tag to hold the bit value of the checkbox}
  422.   if c.Checked then
  423.     fMembers:=fMembers+[b]
  424.   else
  425.     fMembers:=fMembers-[b];
  426.   if assigned(fOnChange) then
  427.     fOnchange(Sender);
  428. end;
  429.  
  430. {------------------------------------------------------------------------------}
  431. { PROCS TO ERECT THE DATASOURCE CONNECTED COMPONENT                            }
  432. {------------------------------------------------------------------------------}
  433.  
  434. constructor TdbBitBox.Create(aOwner:TComponent);
  435. begin
  436.   inherited Create(aOwner);
  437.   inherited ReadOnly := True;
  438.   FDataLink:= TFieldDataLink.Create;
  439.   FDataLink.OnDataChange:= DataChange;
  440.   FDataLink.Control := Self;
  441.   FDataLink.OnEditingChange := EditingChange;
  442.   FDataLink.OnUpdateData := UpdateData;
  443. end;
  444.  
  445. destructor TdbBitBox.Destroy;
  446. begin
  447.   FDataLink.Free;
  448.   FDataLink := nil;
  449.   fCaptions.Free;
  450.   fCaptions:=nil;
  451.   inherited Destroy;
  452. end;
  453.  
  454. procedure TdbBitBox.Notification(AComponent: TComponent;
  455.   Operation: TOperation);
  456. begin
  457.   inherited Notification(AComponent, Operation);
  458.   if (Operation = opRemove) and (FDataLink <> nil) and
  459.     (AComponent = DataSource) then DataSource := nil;
  460. end;
  461.  
  462. {------------------------------------------------------------------------------}
  463. { PLUMBING AND READ-ONLY                                                       }
  464. {------------------------------------------------------------------------------}
  465.  
  466. function TdbBitBox.GetDataSource: TDataSource;
  467. begin
  468.   Result := FDataLink.DataSource;
  469. end;
  470.  
  471. procedure TdbBitBox.SetDataSource(Value: TDataSource);
  472. begin
  473.   FDataLink.DataSource := Value;
  474. end;
  475.  
  476. function TdbBitBox.GetDataField: string;
  477. begin
  478.   Result := FDataLink.FieldName;
  479. end;
  480.  
  481. procedure TdbBitBox.SetDataField(const Value: string);
  482. begin
  483.   FDataLink.FieldName := Value;
  484. end;
  485.  
  486. function TdbBitBox.GetField: TField;
  487. begin
  488.   Result := FDataLink.Field;
  489. end;
  490.  
  491. function TdbBitBox.GetReadOnly: Boolean;
  492. begin
  493.   Result := FDataLink.ReadOnly;
  494. end;
  495.  
  496. procedure TdbBitBox.SetReadOnly(Value: Boolean);
  497. begin
  498.   FDataLink.ReadOnly := Value;
  499. end;
  500.  
  501. {------------------------------------------------------------------------------}
  502. {                                                                              }
  503. {------------------------------------------------------------------------------}
  504.  
  505. procedure TdbBitBox.DataChange(Sender: TObject);
  506. begin
  507.   if FDataLink.Field <> nil then
  508.     Numeric := FDataLink.Field.AsInteger
  509.   else
  510.     if csDesigning in ComponentState then Numeric := 0;
  511. end;
  512.  
  513. procedure TdbBitBox.ChangeSelected(Sender:TObject);
  514. begin
  515.   inherited ChangeSelected(Sender);
  516.   if FDataLink.Field <> nil then
  517.     if not (csDesigning in ComponentState) then
  518.       UpdateData(Sender);
  519. end;
  520.  
  521. procedure TdbBitBox.EditingChange(Sender: TObject);
  522. begin
  523.   inherited ReadOnly := not FDataLink.Editing;
  524. end;
  525.  
  526. procedure TdbBitBox.UpdateData(Sender: TObject);
  527. begin
  528.   if Numeric<>FDataLink.Field.AsInteger then
  529.     if FDataLink.Edit then
  530.       FDataLink.Field.AsInteger:= Numeric;
  531. end;
  532.  
  533.  
  534. {------------------------------------------------------------------------------}
  535. {                                                                              }
  536. {------------------------------------------------------------------------------}
  537.  
  538. end.
  539.